/*
 * logger.cpp
 *
 *  Created on: 2021年2月7日
 *      Author: kimfeng
 */

#include "logger.h"

#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <pthread.h>
#include <boost/date_time/c_time.hpp>

//static bool g_bInThreads = false;
static bool g_bFlushNow = false;
static logger_level g_level = eError;
static const char *g_level_names[] = {"NoLog", "Info", "Error", "Warn", "Debug", "Trace"};
static pthread_mutex_t g_mutex;

void logger_init(logger_level level, bool bFlushNow)
{
	if (level >= eNoLog && level <= eTrace)
		g_level = level;
	g_bFlushNow = bFlushNow;
	pthread_mutex_init(&g_mutex, NULL);
}

void logger_init(const char* sLevel, bool bFlushNow)
{
	logger_init(get_logger_level_byname(sLevel), bFlushNow);
}

void print_debug_message(int level, FILE *f, const char *filename, const char *func, int line, const char *fmt, ...)
{
	if (level > g_level || level >= eUnknown) return ;

	pthread_mutex_lock(&g_mutex);
	switch (level) {
		case eInfo:
			fprintf(f, "[INFO]");
			break;
		case eError:
			fprintf(f, "[ERROR]");
			break;
		case eWarn:
			fprintf(f, "[WARN]");
			break;
		case eDebug:
			fprintf(f, "[DEBUG]");
			break;
		case eTrace:
			fprintf(f, "[TRACE]");
			break;
		default:
			return ;
	}

	struct tm tmNow;
	time_t t;
	switch (level) {
		//case eDebug:
		case eTrace:
			t = time(NULL);
			//boost::date_time::c_time::localtime(&t, &tmNow);
#if defined(__MINGW64__) || defined(__MINGW32__)
			localtime_s(&tmNow, &t);
#else
			localtime_r(&t, &tmNow);
#endif
			fprintf(f, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d] ",
					tmNow.tm_year+1900, tmNow.tm_mon, tmNow.tm_mday,
					tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);

			break;
		default:
			break;
	}

	if (g_level == eTrace)
	{
		fprintf(f, "%s ", filename);
	}

	if (g_level == eTrace || g_level == eDebug)
	{
		fprintf(f, "%s() +%d: ", func, line);
	}

	va_list ap;
	va_start(ap, fmt);\
	vfprintf(f, fmt, ap);
	va_end(ap);
	fprintf(f, "\n");
	if (g_bFlushNow)
		fflush(f);
	pthread_mutex_unlock(&g_mutex);
}

logger_level get_logger_level_byname(const char* sLevel)
{
	logger_level ret = eUnknown;
	int n = sizeof (g_level_names) / sizeof ((g_level_names)[0]);
	for (int i=0; i<n; i++)
	{
		if (strcasecmp(g_level_names[i], sLevel)==0)
		{
			ret = (logger_level)i;
			break;
		}
	}
	return ret;
}

logger_level get_current_logger_level()
{
	return g_level;
}
